/*
 * Copyright 2010, 2011 Matt Oliveri
 *
 * This file is part of JConfigGen
 *
 * JConfigGen is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JConfigGen is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with JConfigGen.  If not, see <http://www.gnu.org/licenses/>.
 */

package atma.jconfiggen;

import java.io.PrintStream;
import java.util.List;
import java.util.Iterator;

/** Common abstract superclass of expression types whose instances evaluate and use the results of multiple, comma-separated subexpressions.
 */
public abstract class TupleExpr extends CoreExpr
{
	private final List<Expr> elems;
	private boolean didStatizing;

	TupleExpr(Config c,String i,List<Expr> l) {super(c,i);elems = l;}

	// We are statizing in hasStats() instead of printStats() in order to avoid calling hasStats() on our elems twice.
	// As a result, doStatizing() is actually also an implementation of hasStats().
	// Since statizing needs to be done, even if hasStats() is not called, printStats() will call doStatizing() if it has not yet been called.
	// didStatizing is used to keep track of this.
	// Statizing needs to be done in a seperate, private method rather than right in hasStats() so that printStats() can call it even if hasStats() gets overridden.
	private boolean doStatizing()
	{
		didStatizing = true;
		Iterator<Expr> si = elems.iterator();
		boolean rtn = super.hasStats();
		if (!si.hasNext()) return rtn;
		boolean statB4 = false;
		Expr s = si.next();
		for (Expr e:elems)
		{
			if (e.hasStats())
			{
				rtn = true;
				statB4 = true;
				while (s != e)
				{
					s.statize();
					s = si.next();
				}
			}
		}
		if (statB4) statBefore();
		return rtn;
	}

	void statBefore() {}
	boolean hasStats() {return doStatizing();}

	void printStatsDlgt(PrintStream out,int tabs) throws InvalidConfigException
	{
		for (Expr e:elems) e.printStats(out,tabs);
		super.printStats(out,tabs);
	}

	// Final because subclasses should override printStatsDlgt() instead, so that doStatizing() is called if needed.
	final void printStats(PrintStream out,int tabs) throws InvalidConfigException
	{
		if (!didStatizing) doStatizing();
		printStatsDlgt(out,tabs);
	}

	final void printElems(PrintStream out)
	{
		Iterator<Expr> i = elems.iterator();
		if (!i.hasNext()) return;
		i.next().printExpr(out);
		while (i.hasNext()) {out.print(',');i.next().printExpr(out);}
	}
}
